#include "U2Rect2D.h"

#include "U2HardwareBufferManager.h"


U2EG_NAMESPACE_USING


#define POSITION_BINDING        0
#define NORMAL_BINDING          1
#define TEXCOORD_BINDING        2


U2Rect2D::U2Rect2D(bool includeTextureCoords, U2HardwareBuffer::Usage vBufUsage)
: U2Renderable()
{
    _initRectangle2D(includeTextureCoords, vBufUsage);
}

/**********************@@@@@@@@@@@@@@@@@@@@@
U2Rect2D::U2Rect2D(const U2String& name, bool includeTextureCoords, U2HardwareBuffer::Usage vBufUsage)
: U2Renderable(name)
{
    _initRectangle2D(includeTextureCoords, vBufUsage);
}
*/

void U2Rect2D::_initRectangle2D(bool includeTextureCoords, U2HardwareBuffer::Usage vBufUsage) 
{
    /*
    // use identity projection and view matrices
    mUseIdentityProjection = true;
    mUseIdentityView = true;
    */

    mRenderOp.vertexData = U2_NEW U2VertexData();

    mRenderOp.indexData = 0;
    mRenderOp.vertexData->vertexCount = 4; 
    mRenderOp.vertexData->vertexStart = 0; 
    mRenderOp.operationType = U2RenderOperation::OT_TRIANGLE_STRIP; 
    mRenderOp.useIndexes = false; 
    mRenderOp.useGlobalInstancingVertexBufferIsAvailable = false;

    U2VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration;
    U2VertexBufferBinding* bind = mRenderOp.vertexData->vertexBufferBinding;

    decl->addElement(POSITION_BINDING, 0, VET_FLOAT3, VES_POSITION);


    U2HardwareVertexBufferSharedPtr vbuf = 
        U2HardwareBufferManager::getSingleton().createVertexBuffer(
        decl->getVertexSize(POSITION_BINDING),
        mRenderOp.vertexData->vertexCount,
        vBufUsage);

    // Bind buffer
    bind->setBinding(POSITION_BINDING, vbuf);

    decl->addElement(NORMAL_BINDING, 0, VET_FLOAT3, VES_NORMAL);

    vbuf = 
        U2HardwareBufferManager::getSingleton().createVertexBuffer(
        decl->getVertexSize(NORMAL_BINDING),
        mRenderOp.vertexData->vertexCount,
        vBufUsage);

    bind->setBinding(NORMAL_BINDING, vbuf);

    float *pNorm = static_cast<float*>(vbuf->lock(U2HardwareBuffer::HBL_DISCARD));
    *pNorm++ = 0.0f;
    *pNorm++ = 0.0f;
    *pNorm++ = 1.0f;

    *pNorm++ = 0.0f;
    *pNorm++ = 0.0f;
    *pNorm++ = 1.0f;

    *pNorm++ = 0.0f;
    *pNorm++ = 0.0f;
    *pNorm++ = 1.0f;

    *pNorm++ = 0.0f;
    *pNorm++ = 0.0f;
    *pNorm++ = 1.0f;

    vbuf->unlock();

    if (includeTextureCoords)
    {
        decl->addElement(TEXCOORD_BINDING, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES);


        U2HardwareVertexBufferSharedPtr tvbuf = 
            U2HardwareBufferManager::getSingleton().createVertexBuffer(
            decl->getVertexSize(TEXCOORD_BINDING),
            mRenderOp.vertexData->vertexCount,
            vBufUsage);

        // Bind buffer
        bind->setBinding(TEXCOORD_BINDING, tvbuf);

        // Set up basic tex coordinates
        setDefaultUVs();
    }

    /**********************@@@@@@@@@@@@@@@@@@@@@
    // set basic white material
    this->setMaterial("BaseWhiteNoLighting");
    */
}

U2Rect2D::~U2Rect2D() 
{
    U2_DELETE mRenderOp.vertexData;
}

void U2Rect2D::setCorners(u2real left, u2real top, u2real right, u2real bottom, bool updateAABB) 
{
    U2HardwareVertexBufferSharedPtr vbuf = 
        mRenderOp.vertexData->vertexBufferBinding->getBuffer(POSITION_BINDING);
    float* pFloat = static_cast<float*>(vbuf->lock(U2HardwareBuffer::HBL_DISCARD));

    *pFloat++ = left;
    *pFloat++ = top;
    *pFloat++ = -1;

    *pFloat++ = left;
    *pFloat++ = bottom;
    *pFloat++ = -1;

    *pFloat++ = right;
    *pFloat++ = top;
    *pFloat++ = -1;

    *pFloat++ = right;
    *pFloat++ = bottom;
    *pFloat++ = -1;

    vbuf->unlock();

    /**********************@@@@@@@@@@@@@@@@@@@@@
    if(updateAABB)
    {
        mBox.setExtents(
            std::min(left, right), std::min(top, bottom), 0,
            std::max(left, right), std::max(top, bottom), 0);
    }
    */
}

/**********************@@@@@@@@@@@@@@@@@@@@@
void U2Rect2D::setNormals(const Vector3 &topLeft, const Vector3 &bottomLeft, const Vector3 &topRight, const Vector3 &bottomRight)
{
    U2HardwareVertexBufferSharedPtr vbuf = 
        mRenderOp.vertexData->vertexBufferBinding->getBuffer(NORMAL_BINDING);
    float* pFloat = static_cast<float*>(vbuf->lock(U2HardwareBuffer::HBL_DISCARD));

    *pFloat++ = topLeft.x;
    *pFloat++ = topLeft.y;
    *pFloat++ = topLeft.z;

    *pFloat++ = bottomLeft.x;
    *pFloat++ = bottomLeft.y;
    *pFloat++ = bottomLeft.z;

    *pFloat++ = topRight.x;
    *pFloat++ = topRight.y;
    *pFloat++ = topRight.z;

    *pFloat++ = bottomRight.x;
    *pFloat++ = bottomRight.y;
    *pFloat++ = bottomRight.z;

    vbuf->unlock();
}
*/

void U2Rect2D::setUVs( const U2Vector2 &topLeft, const U2Vector2 &bottomLeft,
                         const U2Vector2 &topRight, const U2Vector2 &bottomRight)
{
    if( mRenderOp.vertexData->vertexDeclaration->getElementCount() <= TEXCOORD_BINDING )
        return; //Vertex data wasn't built with UV buffer

    U2HardwareVertexBufferSharedPtr vbuf = 
        mRenderOp.vertexData->vertexBufferBinding->getBuffer(TEXCOORD_BINDING);
    float* pFloat = static_cast<float*>(vbuf->lock(U2HardwareBuffer::HBL_DISCARD));

    *pFloat++ = topLeft.x;
    *pFloat++ = topLeft.y;

    *pFloat++ = bottomLeft.x;
    *pFloat++ = bottomLeft.y;

    *pFloat++ = topRight.x;
    *pFloat++ = topRight.y;

    *pFloat++ = bottomRight.x;
    *pFloat++ = bottomRight.y;

    vbuf->unlock();
}

void U2Rect2D::setDefaultUVs()
{
    setUVs( U2Vector2::ZERO, U2Vector2::UNIT_Y, U2Vector2::UNIT_X, U2Vector2::UNIT_SCALE );
}